/*

Miranda IM: the free IM client for Microsoft* Windows*

Copyright 2000-2007 Miranda ICQ/IM project, 
all portions of this codebase are copyrighted to the people 
listed in contributors.txt.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or ( at your option ) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
#include "commonheaders.h"
#include "m_email.h"

namespace NServices 
{
	namespace SendRecvEMail 
	{

		static HANDLE nhMenuItem	= NULL;
		static HANDLE nhExtraIcon	= INVALID_HANDLE_VALUE;
		HANDLE ExtraIcon = INVALID_HANDLE_VALUE;

		/**
		 * This function reads the email address of the contact.
		 *
		 * @param		hContact	- handle to contact to read email from
		 *
		 * @retval	email address
		 * @retval	NULL, if contact does not provide any email address
		 **/
		static LPSTR Get( HANDLE hContact )
		{
			// ignore owner
			if( hContact != NULL ) 
			{
				LPCSTR szProto = DB::Contact::Proto( hContact );
				
				if( szProto != NULL ) 
				{
					LPCSTR	e[2][4] = {
						{ SET_CONTACT_EMAIL,					SET_CONTACT_EMAIL0,					SET_CONTACT_EMAIL1,					"Mye-mail0" },
						{ SET_CONTACT_COMPANY_EMAIL,	SET_CONTACT_COMPANY_EMAIL0, SET_CONTACT_COMPANY_EMAIL1, "MyCompanye-mail0" }
					};

					INT i, j;
					DBVARIANT dbv;

					for( i = 0; i < 2; i++ )
					{
						for( j = 0; j < 4; j++ )
						{
							if( !DB::Setting::GetAStringEx( hContact, USERINFO, szProto, e[i][j], &dbv ) )
							{
								if( mir_strchr( dbv.pszVal, '@' ) )
								{
									return dbv.pszVal;
								}
								DB::Variant::Free( &dbv );
							}
						}
					}
				}
			}
			return NULL;
		}

		/**
		 * Service function that sends emails
		 *
		 * @param	wParam	- handle to contact to send an email to
		 * @param	lParam	- not used
		 *
		 * @retval	0 if email was sent
		 * @retval	1 if no email can be sent
		 **/
		static INT MenuCommand( WPARAM wParam,LPARAM lParam )
		{
			INT result;
			LPSTR val = NULL;

			__try 
			{
				val = Get( ( HANDLE ) wParam );
				if( val )
				{
					LPSTR szUrl;
					INT len;

					len = mir_strlen( val ) + strlen( "mailto:" );

					szUrl = ( LPSTR )_alloca( len + 1 );

					mir_snprintfA( szUrl, len + 1, "mailto:%s", val );
					mir_free( val );

					result = CallService( MS_UTILS_OPENURL, 1, ( LPARAM )szUrl );
				}
				else
				{
					result = 1;
					MsgBox( ( HWND )lParam, MB_OK, LPGENT( "Send e-mail" ), NULL, LPGENT( "Memory allocation error!" ) );
				}
			}
      __except(GetExceptionCode()==EXCEPTION_ACCESS_VIOLATION ? 
								 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) 
			{
				if( val )
				{
					mir_free( val );
				}

				result = 1;
				MsgErr( ( HWND )lParam, LPGENT( "Memory allocation error!" ) );
			}
			return result;
		}

		/***********************************************************************************************************
		 * Event Handler functions
		 ***********************************************************************************************************/

		static INT OnCListRebuildIcons( WPARAM wParam, LPARAM lParam )
		{
			nhExtraIcon = ( HANDLE )CallService( MS_CLIST_EXTRA_ADD_ICON, ( WPARAM )NIcoLib::GetIcon( ICO_BTN_EMAIL ), 0 );
			return 0;
		}

		/**
		 * Notification handler for clist extra icons to be applied for a contact.
		 *
		 * @param wParam	- handle to the contact whose extra icon is to apply
		 * @param	lParam	- not used
		 **/
		static INT OnCListApplyIcons( WPARAM wParam, LPARAM lParam )
		{
			LPSTR val;
			val = Get( ( HANDLE )wParam );
			if(!myGlobals.ExtraIconsServiceExist)
			{				
				IconExtraColumn iec;

				iec.cbSize = sizeof( IconExtraColumn );
				iec.ColumnType = EXTRA_ICON_EMAIL;
				if( val ) 
				{
					iec.hImage = nhExtraIcon;
					mir_free( val );
				}
				else 
				{
					iec.hImage = INVALID_HANDLE_VALUE;
					mir_free( val );
				}
				CallService( MS_CLIST_EXTRA_SET_ICON, wParam, ( LPARAM )&iec );
			}
			else
			{
				EXTRAICON ico;
				ico.cbSize=sizeof(ico);
				ico.hContact=(HANDLE)wParam;
				ico.hExtraIcon=ExtraIcon;
				ico.icoName=val?ICO_BTN_EMAIL:(char *)0;
				mir_free(val);
				CallService(MS_EXTRAICON_SET_ICON, (WPARAM)&ico, 0);
			}
			return 0;
		}

		/**
		 * Notification handler for changed contact settings
		 *
		 * @param	wParam	-	( HANDLE )hContact
		 * @param	lParam	-	( DBCONTACTWRITESETTING* )pdbcws
		 **/
		static INT OnContactSettingChanged( WPARAM wParam, LPARAM lParam )
		{
			if( wParam )
			{
				DBCONTACTWRITESETTING* pdbcws = ( DBCONTACTWRITESETTING* )lParam;

				if( pdbcws )
				{
					if(
						!mir_strncmp( pdbcws->szSetting, SET_CONTACT_EMAIL, 6 ) ||
						!mir_strncmp( pdbcws->szSetting, SET_CONTACT_COMPANY_EMAIL, 13 ) ||
						!mir_strncmp( pdbcws->szSetting, SET_CONTACT_COMPANY_EMAIL, 13 ) ||
						!mir_strncmp( pdbcws->szSetting, "mye-mail0", 9 )
						)
					{
						OnCListApplyIcons( wParam, 0 );
					}
				}
			}
			return 0;
		}

		/**
		 * This function decides whether to show menuitem for sending emails or not.
		 *
		 * @param		wParam	- handle to contact to send an email to
		 * @param		lParam	- not used
		 *
		 * @return	always 0
		 **/
		static INT OnPreBuildMenu( WPARAM wParam, LPARAM lParam )
		{
			CLISTMENUITEM mi;
			LPSTR val;
			
			ZeroMemory( &mi, sizeof( mi ) );
			mi.cbSize = sizeof( mi );
			mi.flags = CMIM_FLAGS;

			val = Get( ( HANDLE )wParam );
			if( val ) 
			{
				mir_free( val );
			}
			else 
			{
				mi.flags = CMIM_FLAGS | CMIF_HIDDEN;
			}
			CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )nhMenuItem, ( LPARAM )&mi );
			return 0;
		}

		/***********************************************************************************************************
		 * public Module Interface functions
		 ***********************************************************************************************************/

		/**
		 * This function enables or disables menuitems.
		 **/
		VOID RebuildMenu()
		{
			static HANDLE hPrebuildMenuHook = NULL;

			if( DB::Setting::GetByte( SET_EXTENDED_EMAILSERVICE, TRUE ) ) 
			{
				if( !hPrebuildMenuHook ) 
				{
					hPrebuildMenuHook = HookEvent( ME_CLIST_PREBUILDCONTACTMENU, OnPreBuildMenu );
				}

				if( !nhMenuItem ) 
				{
					CLISTMENUITEM mi;

					// insert contact menuitem
					ZeroMemory( &mi, sizeof( mi ) );
					mi.cbSize = sizeof( mi );
					mi.position = -2000010000;
					mi.hIcon = NIcoLib::GetIcon( ICO_BTN_EMAIL );
					mi.pszName = "&E-mail";
					mi.pszService = MS_EMAIL_SENDEMAIL;
					nhMenuItem = ( HANDLE )CallService( MS_CLIST_ADDCONTACTMENUITEM, 0, ( LPARAM )&mi );
				}
			}
			else 
			{
				if( hPrebuildMenuHook ) 
				{
					UnhookEvent( ME_CLIST_PREBUILDCONTACTMENU );
					hPrebuildMenuHook = NULL;
				}
				if( nhMenuItem ) 
				{
					CallService( MS_CLIST_REMOVECONTACTMENUITEM, ( WPARAM )nhMenuItem, NULL );
					nhMenuItem = NULL;
				}
			}
		}

		/**
		 * Force all icons to be reloaded.
		 *
		 * @param	wParam	- handle to the contact whose extra icon is to apply
		 * @param lParam	- not used
		 **/
		VOID ApplyCListIcons()
		{
			HANDLE hContact;

			//walk through all the contacts stored in the DB
			for( hContact = DB::Contact::FindFirst();	hContact != NULL;	hContact = DB::Contact::FindNext( hContact ) )
			{
				OnCListApplyIcons( ( WPARAM ) hContact, 0 );
			}
		}

		/**
		 * Enable or disable the replacement of clist extra icons.
		 *
		 * @param	bEnable		- determines whether icons are enabled or not
		 * @param bUpdateDB	- if true the database setting is updated, too.
		 **/
		VOID EnableExtraIcons( BOOLEAN bEnable, BOOLEAN bUpdateDB ) 
		{
			if( myGlobals.HaveCListExtraIcons )
			{
				static HANDLE	hChangedHook			= NULL;
				static HANDLE	hApplyIconHook		= NULL;
				static HANDLE	hRebuildIconsHook = NULL;

				if( bUpdateDB )
				{
					DB::Setting::WriteByte( SET_CLIST_EXTRAICON_EMAIL, bEnable );
				}

				if( bEnable )	// E-mail checkt
				{
					if(myGlobals.ExtraIconsServiceExist)
					{
						EXTRAICON_INFO ico = {0};
						ico.type = EXTRAICON_TYPE_ICOLIB;
						ico.cbSize=sizeof(ico);
						ico.name="email";		//must be the same as the group name in extraicon
						ico.description= "E-mail (uinfoex)";
						ico.descIcon=ICO_BTN_EMAIL;
						ExtraIcon=(HANDLE)CallService(MS_EXTRAICON_REGISTER, (WPARAM)&ico, 0);
						ZeroMemory(&ico,sizeof(ico));
					}

					// hook events
					if( hChangedHook == NULL ) 
					{
						hChangedHook = HookEvent( ME_DB_CONTACT_SETTINGCHANGED, OnContactSettingChanged );
					}
					if( hApplyIconHook == NULL ) 
					{
						hApplyIconHook = HookEvent( ME_CLIST_EXTRA_IMAGE_APPLY, OnCListApplyIcons );
					}
					if( hRebuildIconsHook == NULL ) 
					{
						hRebuildIconsHook = HookEvent( ME_CLIST_EXTRA_LIST_REBUILD, OnCListRebuildIcons );
						OnCListRebuildIcons( 0, 0 );
					}
				}
				else			// E-mail uncheckt
				{
					UnhookEvent( hChangedHook ); 
					hChangedHook = NULL;
					
					UnhookEvent( hApplyIconHook ); 
					hApplyIconHook = NULL;
					
					UnhookEvent( hRebuildIconsHook ); 
					hRebuildIconsHook = NULL;
				}
				ApplyCListIcons();
			}
		}

		/**
		 * This function initially loads the module uppon startup.
		 **/
		VOID OnModulesLoaded()
		{
			EnableExtraIcons( DB::Setting::GetByte( SET_CLIST_EXTRAICON_EMAIL, DEFVAL_CLIST_EXTRAICON_EMAIL ), FALSE );
		}

		/**
		 * This function initially loads the module uppon startup.
		 **/
		VOID LoadModule()
		{
			if( DB::Setting::GetByte( SET_EXTENDED_EMAILSERVICE, TRUE ) ) 
			{
				// prevent default email module from loading
				LPINT disableDefaultModule = ( LPINT )CallService( MS_PLUGINS_GETDISABLEDEFAULTARRAY, 0, 0 );
				disableDefaultModule[DEFMOD_SREMAIL] = TRUE;
					
				// create own email send command
				DestroyServiceFunction( ( HANDLE )hashSetting( MS_EMAIL_SENDEMAIL ) );
				CreateServiceFunction( MS_EMAIL_SENDEMAIL, MenuCommand );
			}
		}

	} /* namespace SendRecvEMail */

} /* namespace NServices */
